/*
 *  sideinfo.c
 *  oE6
 *
 *  Created by Tony Million on 12/12/2008.
 *  Copyright 2008 Tony Million. All rights reserved.
 *
 */

#include "sideinfo.h"
#include "bitstream.h"

int decodeSideInfo(unsigned char * sideinfodata, sideinfo * si, header * head)
{
	unsigned long ch, gr, scfsi_band, region, window;
	
	bitstream	bs;	
	bsinit(&bs, sideinfodata, 32);
	
	
	if(head->MpegVersion == MPEG1)
	{
		si->MainDataBegin = bsgetbits(&bs, 9);
		
		if(head->Channels == 1)
		{
			si->PrivateBits = bsgetbits(&bs, 5);
		}
		else
			si->PrivateBits = bsgetbits(&bs, 3);
		
		for(ch=0; ch<head->Channels; ch++)
			for(scfsi_band=0; scfsi_band<4; scfsi_band++)
				si->ScfSi[ch][scfsi_band] = bsgetbits(&bs, 1);
		
		for(gr=0; gr<2; gr++)
		{
			for(ch=0; ch<head->Channels; ch++)
			{
				si->grinf[gr][ch].Part23Length					= bsgetbits(&bs, 12);
				si->grinf[gr][ch].BigValues						= bsgetbits(&bs, 9);
				si->grinf[gr][ch].GlobalGain					= bsgetbits(&bs, 8);
				
				si->grinf[gr][ch].ScalefacCompress				= bsgetbits(&bs, 4);
				
				si->grinf[gr][ch].WindowSwitchingFlag			= bsgetbits(&bs, 1);
				
				if(si->grinf[gr][ch].WindowSwitchingFlag == 1)
				{
					si->grinf[gr][ch].BlockType					= bsgetbits(&bs, 2);
					if(si->grinf[gr][ch].BlockType == 0)
						return 0;
					
					si->grinf[gr][ch].MixedBlockFlag			= bsgetbits(&bs, 1);
					
					si->grinf[gr][ch].TableSelect[0]			= bsgetbits(&bs, 5);
					si->grinf[gr][ch].TableSelect[1]			= bsgetbits(&bs, 5);
					si->grinf[gr][ch].TableSelect[2]			= 0;
					
					si->grinf[gr][ch].SubblockGain[0]			= bsgetbits(&bs, 3);
					si->grinf[gr][ch].SubblockGain[1]			= bsgetbits(&bs, 3);
					si->grinf[gr][ch].SubblockGain[2]			= bsgetbits(&bs, 3);
					
					// not used in short blocks
					if(	(si->grinf[gr][ch].BlockType == BLOCKTYPE_3WIN) && 
					   (si->grinf[gr][ch].MixedBlockFlag == 0) )
					{
						si->grinf[gr][ch].Region0Count			= 8;
					}
					else
						si->grinf[gr][ch].Region0Count			= 7;
					
					si->grinf[gr][ch].Region1Count				= 20 - si->grinf[gr][ch].Region0Count;
				}
				else
				{
					si->grinf[gr][ch].BlockType					= 0;
					si->grinf[gr][ch].MixedBlockFlag			= 0;
					
					si->grinf[gr][ch].TableSelect[0]			= bsgetbits(&bs, 5);
					si->grinf[gr][ch].TableSelect[1]			= bsgetbits(&bs, 5);
					si->grinf[gr][ch].TableSelect[2]			= bsgetbits(&bs, 5);
					
					si->grinf[gr][ch].SubblockGain[0]			= 0;
					si->grinf[gr][ch].SubblockGain[1]			= 0;
					si->grinf[gr][ch].SubblockGain[2]			= 0;
					
					si->grinf[gr][ch].Region0Count				= bsgetbits(&bs, 4);
					si->grinf[gr][ch].Region1Count				= bsgetbits(&bs, 3);
				}
				
				si->grinf[gr][ch].PreFlag						= bsgetbits(&bs, 1);
				si->grinf[gr][ch].ScalefacScale					= bsgetbits(&bs, 1);
				si->grinf[gr][ch].Count1Table_Select			= bsgetbits(&bs, 1);
			}
		}
	}
	else
	{
		si->MainDataBegin = bsgetbits(&bs, 8);
		
		if(head->Channels == 1)
			si->PrivateBits = bsgetbits(&bs, 1);
		else
			si->PrivateBits = bsgetbits(&bs, 2);
		
		gr=0;
		
		for(ch=0; ch<head->Channels; ch++)
		{
			si->grinf[gr][ch].Part23Length					= bsgetbits(&bs, 12);
			si->grinf[gr][ch].BigValues						= bsgetbits(&bs, 9);
			si->grinf[gr][ch].GlobalGain					= bsgetbits(&bs, 8);
			
			si->grinf[gr][ch].ScalefacCompress				= bsgetbits(&bs, 9);
			
			si->grinf[gr][ch].WindowSwitchingFlag			= bsgetbits(&bs, 1);
			
			if(si->grinf[gr][ch].WindowSwitchingFlag == 1)
			{
				si->grinf[gr][ch].BlockType					= bsgetbits(&bs, 2);
				si->grinf[gr][ch].MixedBlockFlag			= bsgetbits(&bs, 1);
				
				for(region = 0; region < 2; region++)
				{
					si->grinf[gr][ch].TableSelect[region]	= bsgetbits(&bs, 5);
				}
				si->grinf[gr][ch].TableSelect[2]			= 0;
				
				for(window = 0; window < 3; window++)
				{
					si->grinf[gr][ch].SubblockGain[window]	= bsgetbits(&bs, 3);
				}
				
				// not used in short blocks
				if(	(si->grinf[gr][ch].BlockType == BLOCKTYPE_3WIN) && 
				   (si->grinf[gr][ch].MixedBlockFlag == 0) )
				{
					si->grinf[gr][ch].Region0Count			= 8;
				}
				else
					si->grinf[gr][ch].Region0Count			= 7;
				
				si->grinf[gr][ch].Region1Count				= 20 - si->grinf[gr][ch].Region0Count;
			}
			else
			{
				si->grinf[gr][ch].BlockType					= 0;
				
				for(region = 0; region < 3; region++)
				{
					si->grinf[gr][ch].TableSelect[region]	= bsgetbits(&bs, 5);
				}
				
				si->grinf[gr][ch].Region0Count				= bsgetbits(&bs, 4);
				si->grinf[gr][ch].Region1Count				= bsgetbits(&bs, 3);
			}
			
			si->grinf[gr][ch].ScalefacScale					= bsgetbits(&bs, 1);
			si->grinf[gr][ch].Count1Table_Select			= bsgetbits(&bs, 1);
		}
	}

	return 1;
}